﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Globalization;
using System.Reflection;
using Newtonsoft.Json.Linq;

namespace DidaManager.Models.JsonConvert
{
    /// <summary>
    /// 设备下载配置（目标文件结构）
    /// </summary>
    public class DeviceConfigToDownloadFile
    {
        [JsonPropertyName("DEVConfigs")]
        public List<DevPortConfig> DEVConfigs { get; set; } = new List<DevPortConfig>();

        /// <summary>
        /// 从文件读取并解析为设备下载配置
        /// </summary>
        public static DeviceConfigToDownloadFile ParseFromJson(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"文件不存在: {filePath}");
            }

            string jsonString = File.ReadAllText(filePath, new UTF8Encoding(false));
            if (string.IsNullOrWhiteSpace(jsonString))
            {
                throw new ArgumentException("JSON内容不能为空");
            }

            var options = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };

            return JsonSerializer.Deserialize<DeviceConfigToDownloadFile>(jsonString, options) ?? new DeviceConfigToDownloadFile();
        }

        /// <summary>
        /// 保存为JSON文件
        /// </summary>
        public static void SaveToJson(DeviceConfigToDownloadFile config, string filePath)
        {
            string jsonContent = JsonSerializer.Serialize(config, JsonSerializerOptionsManager.Compact);
            File.WriteAllText(filePath, jsonContent, new UTF8Encoding(false));
        }

        /// <summary>
        /// 从数据库JSON字符串解析设备配置并转换为下载格式后覆盖保存
        /// </summary>
        /// <param name="filePath">文件路径（输入原始DB JSON，输出下载JSON）</param>
        public static void ParseDbJsonAndSave(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"文件不存在: {filePath}");
            }

            string jsonContent = File.ReadAllText(filePath, new UTF8Encoding(false));
            if (string.IsNullOrWhiteSpace(jsonContent))
            {
                throw new ArgumentException("JSON内容不能为空");
            }

            // 输入为数组
            var jsonArray = JArray.Parse(jsonContent);
            var dbDevices = new List<DatabaseDeviceConfig>();

            foreach (JObject devJson in jsonArray)
            {
                var dev = MapJsonToObject<DatabaseDeviceConfig>(devJson);
                dbDevices.Add(dev);
            }

            var downloadConfig = ConvertToDownloadFormat(dbDevices);
            SaveToJson(downloadConfig, filePath);
        }

        /// <summary>
        /// 通用的 JSON 到对象映射方法
        /// </summary>
        private static T MapJsonToObject<T>(JObject json) where T : class, new()
        {
            var obj = new T();
            var properties = typeof(T).GetProperties();

            foreach (var prop in properties)
            {
                var jsonPropertyName = GetJsonPropertyName(prop);
                if (json.TryGetValue(jsonPropertyName, out JToken? value) && value != null)
                {
                    SetPropertyValue(obj, prop, value);
                }
            }

            return obj;
        }

        private static string GetJsonPropertyName(PropertyInfo prop)
        {
            var attr = prop.GetCustomAttribute<JsonPropertyNameAttribute>();
            return attr?.Name ?? prop.Name;
        }

        private static void SetPropertyValue(object obj, PropertyInfo prop, JToken value)
        {
            if (obj == null) return;

            try
            {
                if (prop.PropertyType == typeof(string))
                {
                    prop.SetValue(obj, value.ToString());
                    return;
                }
                if (prop.PropertyType == typeof(int))
                {
                    if (value.Type == JTokenType.Integer)
                    {
                        prop.SetValue(obj, value.Value<int>());
                    }
                    else
                    {
                        int.TryParse(value.ToString(), out int v);
                        prop.SetValue(obj, v);
                    }
                    return;
                }
                if (prop.PropertyType == typeof(bool))
                {
                    if (value.Type == JTokenType.Boolean)
                    {
                        prop.SetValue(obj, value.Value<bool>());
                    }
                    else
                    {
                        bool.TryParse(value.ToString(), out bool b);
                        prop.SetValue(obj, b);
                    }
                    return;
                }
                if (prop.PropertyType.IsClass && prop.PropertyType != typeof(string))
                {
                    if (value is JObject nested)
                    {
                        var nestedObj = Activator.CreateInstance(prop.PropertyType);
                        if (nestedObj != null)
                        {
                            foreach (var nestedProp in prop.PropertyType.GetProperties())
                            {
                                var name = GetJsonPropertyName(nestedProp);
                                if (nested.TryGetValue(name, out var nv) && nv != null)
                                {
                                    SetPropertyValue(nestedObj, nestedProp, nv);
                                }
                            }
                            prop.SetValue(obj, nestedObj);
                        }
                    }
                    return;
                }
            }
            catch
            {
                // ignore and leave default
            }
        }

        /// <summary>
        /// 将数据库设备配置转换为下载格式
        /// </summary>
        private static DeviceConfigToDownloadFile ConvertToDownloadFormat(List<DatabaseDeviceConfig> dbDevices)
        {
            var result = new DeviceConfigToDownloadFile
            {
                DEVConfigs = new List<DevPortConfig>()
            };

            // 按端口ID分组
            var groups = new Dictionary<int, DevPortConfig>();

            foreach (var dev in dbDevices)
            {
                int portId = dev.MonitorPortId;
                if (!groups.TryGetValue(portId, out var portConfig))
                {
                    portConfig = new DevPortConfig
                    {
                        PortName = dev.PortName,
                        DevList = new List<DevInfo>()
                    };
                    groups[portId] = portConfig;
                }

                var info = new DevInfo
                {
                    DevName = dev.Name ?? string.Empty,
                    OpcPath = dev.Extra?.OpcPath ?? string.Empty,
                    DevAddr = ParseAddress(dev.Extra?.Address ?? string.Empty, dev.Extra?.IsHex ?? false),
                    FloatOrder = MapByteOrder4(dev.Extra?.FloatByteOrder ?? string.Empty),
                    LongOrder = MapByteOrder4(dev.Extra?.Int32ByteOrder ?? string.Empty),
                    LongLongOrder = MapByteOrder8(dev.Extra?.Int64ByteOrder ?? string.Empty),
                    DoubleOrder = MapByteOrder8(dev.Extra?.DoubleByteOrder ?? string.Empty),
                    ProtocolAddress = dev.Extra?.ProtocolAddress ?? string.Empty,
                    DevicePassword = dev.Extra?.DevicePassword ?? string.Empty,
                    Id = dev.Id
                };

                portConfig.DevList.Add(info);
            }

            result.DEVConfigs.AddRange(groups.Values);
            return result;
        }

        private static int ParseAddress(string address, bool isHex)
        {
            if (string.IsNullOrWhiteSpace(address)) return 0;
            if (isHex)
            {
                if (address.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
                {
                    address = address.Substring(2);
                }
                return int.TryParse(address, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int hexVal) ? hexVal : 0;
            }
            return int.TryParse(address, NumberStyles.Integer, CultureInfo.InvariantCulture, out int decVal) ? decVal : 0;
        }

        // 简单的字节序映射：ABCD=1, CDAB=2, BADC=3, DCBA=4；未知返回0
        private static int MapByteOrder4(string order)
        {
            return (order ?? string.Empty).ToUpperInvariant() switch
            {
                "ABCD" => 1,
                "CDAB" => 2,
                "BADC" => 3,
                "DCBA" => 4,
                _ => 0
            };
        }

        // 简单的8字节序映射：ABCDEFGH=1，GHEFCDAB=2，BADCFEHG=3，HGFEDCBA=4；其它未知返回0
        private static int MapByteOrder8(string order)
        {
            return (order ?? string.Empty).ToUpperInvariant() switch
            {
                "ABCDEFGH" => 1,
                "GHEFCDAB" => 2,
                "BADCFEHG" => 3,
                "HGFEDCBA" => 4,
                _ => 0
            };
        }
    }

    /// <summary>
    /// 单个端口下的设备集合配置
    /// </summary>
    public class DevPortConfig
    {
        [JsonPropertyName("PortName")]
        public string PortName { get; set; } = string.Empty;

        [JsonPropertyName("DevList")]
        public List<DevInfo> DevList { get; set; } = new List<DevInfo>();
    }

    /// <summary>
    /// 设备信息
    /// </summary>
    public class DevInfo
    {
        [JsonPropertyName("DevName")]
        public string DevName { get; set; } = string.Empty;

        [JsonPropertyName("OpcPath")]
        public string OpcPath { get; set; } = string.Empty;

        [JsonPropertyName("DevAddr")]
        public int DevAddr { get; set; }

        [JsonPropertyName("FloatOrder")]
        public int FloatOrder { get; set; }

        [JsonPropertyName("LongOrder")]
        public int LongOrder { get; set; }

        [JsonPropertyName("LongLongOrder")]
        public int LongLongOrder { get; set; }

        [JsonPropertyName("DoubleOrder")]
        public int DoubleOrder { get; set; }

        [JsonPropertyName("ProtocolAddress")]
        public string ProtocolAddress { get; set; } = string.Empty;

        [JsonPropertyName("DevicePassword")]
        public string DevicePassword { get; set; } = string.Empty;

        [JsonPropertyName("id")]
        public int Id { get; set; }
    }

    // ========== 数据库JSON结构定义 ==========

    public class DatabaseDeviceConfig
    {
        [JsonPropertyName("id")]
        public int Id { get; set; }

        [JsonPropertyName("monitor_port_id")]
        public int MonitorPortId { get; set; }

        [JsonPropertyName("port_name")]
        public string PortName { get; set; } = string.Empty;

        [JsonPropertyName("name")]
        public string Name { get; set; } = string.Empty;

        [JsonPropertyName("description")]
        public string Description { get; set; } = string.Empty;

        [JsonPropertyName("activeTab")]
        public string ActiveTab { get; set; } = string.Empty;

        [JsonPropertyName("extra")]
        public DatabaseDeviceExtra Extra { get; set; } = new DatabaseDeviceExtra();
    }

    public class DatabaseDeviceExtra
    {
        [JsonPropertyName("address")]
        public string Address { get; set; } = string.Empty;

        [JsonPropertyName("isHex")]
        public bool IsHex { get; set; }

        [JsonPropertyName("floatByteOrder")]
        public string FloatByteOrder { get; set; } = string.Empty;

        [JsonPropertyName("int32ByteOrder")]
        public string Int32ByteOrder { get; set; } = string.Empty;

        [JsonPropertyName("int64ByteOrder")]
        public string Int64ByteOrder { get; set; } = string.Empty;

        [JsonPropertyName("doubleByteOrder")]
        public string DoubleByteOrder { get; set; } = string.Empty;

        [JsonPropertyName("protocolAddress")]
        public string ProtocolAddress { get; set; } = string.Empty;

        [JsonPropertyName("devicePassword")]
        public string DevicePassword { get; set; } = string.Empty;

        [JsonPropertyName("opc_path")]
        public string OpcPath { get; set; } = string.Empty;
    }
}
